package com.googlecode.lightest.core

import org.testng.internal.annotations.IAnnotationFinder
import org.testng.internal.annotations.JDK14AnnotationFinder
import org.testng.internal.ClassHelper
import org.testng.ITestClass
import org.testng.SuiteRunner
import org.testng.TestNG
import org.testng.xml.XmlSuite
import org.testng.xml.XmlTest

/**
 * This class delves into TestNG internals in order to produce a listing of
 * tests that are represented by a set of suites. Normally, TestNG discovers
 * this list as it is running the tests. For reporting purposes, we would like
 * to be able to have this information a priori, so we can generate a listing
 * of pending tests.
 */
class TestInstanceFinder {

    TestInstanceFinder() {}

    /**
     * Finds and returns all TestInstances represented by a list of suites to
     * be run. setTestSuites() or equivalent should have been called on the
     * wrapped TestNG instance before this method is invoked.
     *
     * @param testng  the TestNG instance from which to derive test instance
     *                information
     */
    TestRegistry find(TestNG testng) {
        assert testng != null
        assert testng.m_suites != null

        def registry = new TestRegistry()

        for (XmlSuite suite in testng.m_suites) {
            def suiteRunner = createSuiteRunner(testng, suite)

            for (XmlTest test in suite.getTests()) {
                def testRunner = createTestRunner(suiteRunner, test)
                def runInfo = testRunner.m_runInfo

                for (ITestClass testClass in testRunner.getIClass()) {
                    for (testMethod in testClass.getTestMethods()) {
                        // take explicit inclusions / exclusions into account
                        if (! runInfo.includeMethod(testMethod, true)) {
                            continue
                        }
                        
                        for (i in 1..testMethod.getInvocationCount()) {
                            // getSignature() is not exposed in the interface
                            registry.add(new TestInstance(suite.getName(),
                                test.getName(), testClass.getName(),
                                testMethod.getMethodName(),
                                testMethod.getSignature()))
                        }
                    }
                }
            }
        }

        return registry
    }
    
    protected SuiteRunner createSuiteRunner(TestNG testng, XmlSuite xmlSuite) {
        def transformer = testng.getAnnotationTransformer()

        assert transformer != null

        IAnnotationFinder[] finders = [
            new JDK14AnnotationFinder(transformer),
            ClassHelper.createJdkAnnotationFinder(transformer)
        ]

        return new SuiteRunner(xmlSuite, testng.getOutputDirectory(), finders)
    }

    protected org.testng.TestRunner createTestRunner(SuiteRunner suiteRunner,
        XmlTest xmlTest)
    {
        return (suiteRunner.buildRunnerFactory(suiteRunner.m_testlisteners)
            .newTestRunner(suiteRunner, xmlTest))
    }
}

